package com.google.code.mircle.core;

import java.io.File;
import java.util.concurrent.atomic.AtomicBoolean;

public abstract class Worker {

    public static class Status {
        // delay in seconds before retry, 0 - downloading
        public int delay;
        // total bytes downloaded
        public long current;
        // size of download, null unknown total
        public Long total;
        // download title
        public String title;
        // download rate
        public long downloadRate;
        public long downloadRateAverage;
        // upload rate (system trafic for direct downloads?)
        public long uploadRate;

        public Status(long total, long current, String title) {
            this.current = current;
            this.total = total;
            this.title = title;
        }

        public Status(long total, long current, String title, int delay) {
            this.current = current;
            this.total = total;
            this.title = title;
            this.delay = delay;
        }

        public Status(Long total, long current, String title, int delay, long download, long avg) {
            this.current = current;
            this.total = total;
            this.title = title;
            this.delay = delay;
            this.downloadRate = download;
            this.downloadRateAverage = avg;
        }

        public Status(long total, long current, String title, long download, long avg) {
            this.current = current;
            this.total = total;
            this.title = title;
            this.downloadRate = download;
            this.downloadRateAverage = avg;
        }
    }

    Runnable notify;

    protected AtomicBoolean stop = new AtomicBoolean(false);

    public static enum DownloadState {
        // just created
        DOWNLOAD_NEW,

        // downloading
        DOWNLOAD_START,

        // queued for downloading
        DOWNLOAD_QUEUED,

        // done - success
        DOWNLOAD_COMPLETE,

        // stop by user
        DOWNLOAD_STOP,

        // failed
        DOWNLOAD_FAILED
    }

    public static class State {
        public DownloadState downloadState;
    }

    /**
     * Give us your persistent state.
     * 
     * @return stat object
     */
    protected abstract State getState();

    /**
     * call each time state / progress is changed
     */
    protected void changed() {
        notify.run();
    }

    abstract protected void run();

    public void run(Runnable notify) {
        this.notify = notify;

        run();
    }

    /**
     * Check if source has a conflikt in source (the same source).
     * 
     * @param w
     * @return True if it is the same url
     */
    public boolean checkSource(Worker w) {
        return getSource().equals(w.getSource());
    }

    /**
     * Check if here a some conflickts with target files (cross files on the
     * same / different download target). App should show the dialog which shows
     * worker1 and worker2 with conflicts and files tree with highlight a
     * problem.
     * 
     * @param w
     * @return True - if here is some conflicts
     */
    public boolean checkTarget(Worker w) {
        return false;
    }

    /**
     * change state to start. override to control state change.
     */
    public void start() {
        stop.set(false);

        synchronized (getState()) {
            getState().downloadState = DownloadState.DOWNLOAD_START;
        }
    }

    /**
     * change state to queued. override to control state change.
     */
    public void queued() {
        synchronized (getState()) {
            getState().downloadState = DownloadState.DOWNLOAD_QUEUED;
        }
    }

    /**
     * change state to stop. override to control state change.
     */
    public void stop() {
        synchronized (getState()) {
            getState().downloadState = DownloadState.DOWNLOAD_STOP;
        }

        stop.set(true);
    }

    public void close() {
        stop.set(true);
    }

    /**
     * save current state in xml form.
     * 
     * @return state
     */
    abstract public State save();

    /**
     * load state
     * 
     * @param s
     */
    abstract public void load(State s);

    /**
     * Show target file / directory
     * 
     * @return
     */
    abstract public File getTarget();

    /**
     * get source
     * 
     * @return
     */
    abstract public String getSource();

    /**
     * Status text representation.
     * 
     * @return status
     */
    abstract public Status status();

    public DownloadState getDownloadState() {
        synchronized (getState()) {
            return getState().downloadState;
        }
    }

}
